import Singlelon from './Singlelon';
const { ccclass, property } = cc._decorator;
@ccclass
export default class Emitter extends Singlelon<Emitter>() {
    //用于发送消息
    //用于存储不同消息对应的监听者
    //一个消息有多个监听者
    private _mapListener: Map<string, Listener[]> = new Map();
    get map() {
        return this._mapListener;
    }

    //注册，将这个监听者存入到容器中
    on(msgName: string, target: any, cb: Function, isOnce: boolean = false) {
        if (msgName.length <= 0 || !msgName || !target || !cb) {
            return;
        }
        let listener: Listener = new Listener(msgName, target, cb, isOnce);
        //将这个监听对象保存到容器中
        //这个消息是否存在
        let arrListener = this._mapListener.get(msgName);
        if (!arrListener) {
            //如果这个消息不存在，就将这个消息创建，并把它存入到容器中，
            arrListener = [];
            this._mapListener.set(msgName, arrListener);
        }
        //判断这个监听对象是否存在
        for (let i = 0; i < arrListener.length; i++) {
            if (arrListener[i].isEquals(listener)) {
                cc.error("已经注册");
                return;
            }
        }
        //将这个监听对象放到对应的监听数组中
        arrListener.push(listener);

    }
    //注册一次
    once(msgName: string, target: any, cb: Function) {
        this.on(msgName, target, cb, true);
    }


    //发送消息
    emit(msgName: string, ...rest: any[]) {
        if (!msgName || msgName.length <= 0) {
            return;
        }
        let arrListener = this._mapListener.get(msgName);
        if (!arrListener) {
            return;
        }
        for (let i = 0; i < arrListener.length; i++) {
            let listener = arrListener[i];
            //不要忘记指定对象
            listener.cb.apply(listener.target, rest);
            if (listener.isOnce) {
                arrListener.splice(i--, 1);
            }
        }
        //如果这个数组为空，就将这个消息从容器中删除
        if (arrListener.length <= 0) {
            this._mapListener.delete(msgName);
        }
    }


    //关闭
    //没有参数：代表关闭所有消息
    //一个参数：代表关闭某个消息中的所有监听对象
    //两个参数：代表关闭某个消息中的所有这个监听对象的listener
    //三个参数，代表关闭某个消息中的具有这个回调函数的监听对象
    off(...rest: any[]) {
        let args = Array.from(arguments);

        let length = args.length;
        if (length <= 0) {
            //没有参数：代表关闭所有消息
            //移除所有监听者
            this._mapListener.clear();
            return;
        }
        let msgName = args[0];
        if (typeof msgName != 'string' || !this._mapListener.has(msgName)) {
            cc.error("第一个参数必须是字符串且名字必须正确");
            return;
        }
        if (length <= 1) {
            //一个参数：代表关闭某个消息中的所有监听对象
            this._mapListener.delete(msgName);
            return;
        }
        let arrListener = this._mapListener.get(msgName);

        if (args[1] instanceof Function) {
            //第二个参数不能是函数
            return;
        }
        if (length <= 2) {
            //两个参数：代表关闭某个消息中的所有这个监听对象的listener
            //代表关闭某个消息中的这个
            for (let i = 0; i < arrListener.length; i++) {
                if (arrListener[i].target == args[1]) {
                    arrListener.splice(i--, 1);
                }
            }
            if (arrListener.length <= 0) {
                this._mapListener.delete(msgName);
            }
            return;
        }
        if (length <= 3) {
            //三个参数，代表关闭某个消息中的具有这个回调函数的监听对象
            for (let i = 0; i < arrListener.length; i++) {
                if (arrListener[i].target == args[1] && arrListener[i].cb == args[2]) {
                    arrListener.splice(i, 1);
                    break;
                }
            }
            if (arrListener.length <= 0) {
                this._mapListener.delete(msgName);
            }
        }
    }
}

export class Listener {
    //监听者类
    //消息名
    private _msgName: string = "";
    //监听者对象
    private _target: any = null;
    get target() {
        return this._target;
    }
    //发送消息执行的回调函数
    private _cb: Function = null;
    get cb() {
        return this._cb;
    }
    //是否注册一次
    private _isOnce: boolean = null;
    get isOnce() {
        return this._isOnce;
    }
    //给对象的属性进行初始化
    constructor(msgName: string, target: any, cb: Function, isOnce: boolean) {
        this._msgName = msgName;
        this._target = target;
        this._cb = cb;
        this._isOnce = isOnce;
    }
    //判断是否存在此监听对象
    isEquals(listenerIn: Listener) {
        return this._msgName == listenerIn._msgName
            && this._target == listenerIn.target && this._cb == listenerIn.cb;
    }

}
